﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SocketProject
{
    public partial class Frm_TCPServer : Form
    {
        public enum MessageType
        {
            ASCII,
            UTF8,
            Hex,
            File,
            JSON
        }

        /*服务器端程序的编写步骤
            第一步：调用socket()函数创建一个用于通信的套接字。
            第二步：给已经创建的套接字绑定一个端口号，这一般通过设置网络套接
            口地址和调用bind()函数来实现
            第三步：调用listen（）函数使套接字成为一个监听套接字。
            第四步：调用accept(）函数来接受客户端的连接，这是就可以和客户端通信
            第五步：处理客户端的连接请求。
            第六步：终止连接*/

        private Socket socket;

        //创建字典集合

        private Dictionary<string, Socket> CurrentClientlist = new Dictionary<string, Socket>();

        public Frm_TCPServer()
        {
            InitializeComponent();
            this.Load += Frm_TCPServer_Load;
        }

        private void Frm_TCPServer_Load(object sender, EventArgs e)
        {
            this.lst_Rcv.Columns[1].Width = this.lst_Rcv.ClientSize.Width - this.lst_Rcv.Columns[0].Width;
        }

        private void SelectFile_Btn_Click(object sender, EventArgs e)
        {
        }

        /// <summary>
        /// 开启服务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StartServer_Btn_Click(object sender, EventArgs e)
        {
            //第一步：调用socket()函数创建一个用于通信的套接字。
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(this.ServerIp_txt.Text), int.Parse(this.ServerPort_txt.Text));
            try
            {
                socket.Bind(ipe);
            }
            catch (Exception ex)
            {
                //写入日志
                Addlog(2, "服务开启失败" + ex.Message);
                //ss
                return;
            }

            //第三步：调用listen（）函数使套接字成为一个监听套接字。
            socket.Listen(10);

            //创建一个监听的线程
            Task.Run(new Action(() =>
            {
                CheckListening();
            }));
            Addlog(0, "服务开启成功");
            this.StartServer_Btn.Enabled = false;
        }

        /// <summary>
        /// 检查监听的线程方法体
        /// </summary>
        private void CheckListening()
        {
            while (true)
            {
                //第四步：调用accept(）函数来接受客户端的连接，这是就可以和客户端通信
                Socket socketClient = socket.Accept();

                string client = socketClient.RemoteEndPoint.ToString();

                Addlog(0, client + "上线了");

                CurrentClientlist.Add(client, socketClient);

                UpdateOnline(client, true);

                Task.Run(new Action(() =>
                {
                    ReceiveMessage(socketClient);
                }));
            }
        }

        /// <summary>
        /// 接收客户端数据的方法体多线程接收数据
        /// </summary>
        /// <param name="socketClient"></param>
        private void ReceiveMessage(Socket socketClient)
        {
            while (true)
            {
                //创建一个缓冲区
                byte[] buffer = new byte[1024 * 1024 * 10];

                string client = socketClient.RemoteEndPoint.ToString();

                int length = -1;
                //第五步：处理客户端的连接请求。
                try
                {
                    length = socketClient.Receive(buffer);
                }
                catch (Exception)
                {
                    UpdateOnline(client, false);
                    Addlog(0, client + "下线了");
                    CurrentClientlist.Remove(client);

                    break;
                }

                if (length > 0)
                {
                    string msg = string.Empty;
                    MessageType type = (MessageType)buffer[0];
                    switch (type)
                    {
                        case MessageType.ASCII:
                            msg = Encoding.ASCII.GetString(buffer, 1, length - 1);
                            Addlog(0, client + ": " + msg);
                            break;

                        case MessageType.UTF8:
                            msg = Encoding.UTF8.GetString(buffer, 1, length - 1);
                            Addlog(0, client + ": " + msg);
                            break;

                        case MessageType.Hex:
                            msg = HexGetString(buffer, 1, length - 1);
                            Addlog(0, client + ": " + msg);

                            break;

                        case MessageType.File:
                            Invoke(new Action(() =>
                            {
                                SaveFileDialog sfd = new SaveFileDialog();
                                sfd.Filter = "txt files(*.txt)|*.txt|xls files(*.xls)|*.xls|xlsx files(*.xlsx)|*.xlsx|All files(*.*)|*.*";
                                if (sfd.ShowDialog() == DialogResult.OK)
                                {
                                    string fileSavePath = sfd.FileName;
                                    using (FileStream fs = new FileStream(fileSavePath, FileMode.Create))
                                    {
                                        fs.Write(buffer, 1, length - 1);
                                    }
                                    Addlog(0, "文件成功保存至" + fileSavePath);
                                }
                            }));
                            break;

                        case MessageType.JSON:
                            Invoke(new Action(() =>
                            {
                                string res = Encoding.Default.GetString(buffer, 1, length);
                                List<Employee> employees = JSONHelper.JsonToEntity<List<Employee>>(res);
                                new Form1(employees).ShowDialog();
                            }));
                            break;

                        default:
                            break;
                    }
                    // string msg = Encoding.Default.GetString(buffer, 0, length);
                }
                else
                {
                    UpdateOnline(client, false);
                    Addlog(0, client + "下线了");
                    CurrentClientlist.Remove(client);
                    break;
                }
            }
        }

        #region 接收信息的方法

        private string CurrentTime
        {
            get { return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); }
        }

        private void Addlog(int index, string info)
        {
            if (!this.lst_Rcv.InvokeRequired)
            {
                ListViewItem item = new ListViewItem("" + CurrentTime, index);
                item.SubItems.Add(info);
                lst_Rcv.Items.Insert(lst_Rcv.Items.Count, item);
            }
            else
            {
                Invoke(new Action(() =>
                {
                    ListViewItem item = new ListViewItem("" + CurrentTime, index);
                    item.SubItems.Add(info);
                    lst_Rcv.Items.Insert(lst_Rcv.Items.Count, item);
                }));
            }
        }

        #endregion 接收信息的方法

        #region 在线列表的更新

        private void UpdateOnline(string client, bool operate)
        {
            if (!this.OnLineList_list.InvokeRequired)
            {
                if (operate)
                {
                    this.OnLineList_list.Items.Add(client);
                }
                else
                {
                    foreach (string item in this.OnLineList_list.Items)
                    {
                        if (item == client)
                        {
                            this.OnLineList_list.Items.Remove(item);
                            break;
                        }
                    }
                }
            }
            else
            {
                Invoke(new Action(() =>
                {
                    if (operate)
                    {
                        this.OnLineList_list.Items.Add(client);
                    }
                    else
                    {
                        foreach (string item in this.OnLineList_list.Items)
                        {
                            if (item == client)
                            {
                                this.OnLineList_list.Items.Remove(item);
                                break;
                            }
                        }
                    }
                }));
            }
        }

        #endregion 在线列表的更新

        private void SendMessage_Btn_Click(object sender, EventArgs e)
        {
            if (this.OnLineList_list != null && OnLineList_list.SelectedItems.Count != 0 && this.OnLineList_list.SelectedItem.ToString() != null)
            {
                foreach (var item in this.OnLineList_list.SelectedItems)
                {
                    string client = item.ToString();
                    CurrentClientlist[client].Send(Encoding.Default.GetBytes(this.Sendtxt.Text.Trim()));
                }
            }
            else
            {
                MessageBox.Show("请选择你要发送的客户端对象！", "发送消息");
            }
        }

        private void GroupSendSay_Btn_Click(object sender, EventArgs e)
        {
            if (this.OnLineList_list.Items.Count > 0)
            {
                foreach (string item in this.OnLineList_list.Items)
                {
                    CurrentClientlist[item].Send(Encoding.Default.GetBytes(this.Sendtxt.Text.Trim()));
                }
            }
            else
            {
                MessageBox.Show("当前连接对象为0!", "发送消息");
            }
        }

        private void StartClient_Btn_Click(object sender, EventArgs e)
        {
            new Frm_TcpClient().Show();
        }

        /// <summary>
        /// 16进制字符串处理
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="start"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        private string HexGetString(byte[] buffer, int start, int length)
        {
            string Result = string.Empty;
            if (buffer != null && buffer.Length >= start + length)
            {
                //截取字节数组
                Byte[] res = new Byte[length];
                Array.Copy(buffer, start, res, 0, length);

                string Hex = Encoding.Default.GetString(res, 0, res.Length);
                if (Hex.Contains(" "))
                {
                    string[] str = Regex.Split(Hex, "\\s+", RegexOptions.IgnoreCase);
                    foreach (var st in str)
                    {
                        Result += "0x" + st + "";
                    }
                }
                else
                {
                    Result += "0x" + Hex;
                }
            }
            else
            {
                Result = "Error";
            }
            return Result;
        }

        private void SendAscII_Btn_Click(object sender, EventArgs e)
        {
            if (this.OnLineList_list != null && OnLineList_list.SelectedItems.Count != 0 && this.OnLineList_list.SelectedItem.ToString() != null)
            {
                byte[] send = Encoding.ASCII.GetBytes((this.Sendtxt.Text.Trim()));

                //创建最终发送的数据
                byte[] sendMsg = new byte[send.Length + 1];

                //整体拷贝数组
                Array.Copy(send, 0, sendMsg, 1, send.Length);

                //给首字节赋值
                sendMsg[0] = (byte)MessageType.ASCII;
                foreach (var item in this.OnLineList_list.SelectedItems)
                {
                    string client = item.ToString();

                    CurrentClientlist[client]?.Send(sendMsg);
                }
                this.Sendtxt.Clear();
            }
            else
            {
                MessageBox.Show("请选择你要发送的客户端对象！", "发送消息");
            }
        }

        private void btn_SendUTF8_Click(object sender, EventArgs e)
        {
            if (this.OnLineList_list != null && OnLineList_list.SelectedItems.Count != 0 && this.OnLineList_list.SelectedItem.ToString() != null)
            {
                byte[] send = Encoding.UTF8.GetBytes((this.Sendtxt.Text.Trim()));

                //创建最终发送的数据
                byte[] sendMsg = new byte[send.Length + 1];

                //整体拷贝数组
                Array.Copy(send, 0, sendMsg, 1, send.Length);

                //给首字节赋值
                sendMsg[0] = (byte)MessageType.UTF8;
                foreach (var item in this.OnLineList_list.SelectedItems)
                {
                    string client = item.ToString();

                    CurrentClientlist[client]?.Send(sendMsg);
                }
                this.Sendtxt.Clear();
            }
            else
            {
                MessageBox.Show("请选择你要发送的客户端对象！", "发送消息");
            }
        }

        private void btn_SendHex_Click(object sender, EventArgs e)
        {
            if (this.OnLineList_list != null && OnLineList_list.SelectedItems.Count != 0 && this.OnLineList_list.SelectedItem.ToString() != null)
            {
                byte[] send = Encoding.Default.GetBytes((this.Sendtxt.Text.Trim()));

                //创建最终发送的数据
                byte[] sendMsg = new byte[send.Length + 1];

                //整体拷贝数组
                Array.Copy(send, 0, sendMsg, 1, send.Length);

                //给首字节赋值
                sendMsg[0] = (byte)MessageType.Hex;
                foreach (var item in this.OnLineList_list.SelectedItems)
                {
                    string client = item.ToString();

                    CurrentClientlist[client]?.Send(sendMsg);
                }
                this.Sendtxt.Clear();
            }
            else
            {
                MessageBox.Show("请选择你要发送的客户端对象！", "发送消息");
            }
        }

        private void btn_SendJson_Click(object sender, EventArgs e)
        {
            if (this.OnLineList_list != null && OnLineList_list.SelectedItems.Count != 0 && this.OnLineList_list.SelectedItem.ToString() != null)
            {
                List<Employee> list = new List<Employee>()
            {
                new Employee()
                {
                    Id = 1,
                    Name = "Test2",
                    Level ="A",
                    Age = 22
                },
                new Employee()
                {
                    Id = 2,
                    Name = "Test1",
                    Level ="A",
                    Age = 26
                },
                new Employee()
                {
                    Id = 3,
                    Name = "Test4",
                    Level ="C",
                    Age = 22
                }
            };

                string str = JSONHelper.EntityToJSON(list);

                byte[] send = Encoding.Default.GetBytes(str);

                byte[] sendMsg = new byte[send.Length + 1];

                Array.Copy(send, 0, sendMsg, 1, send.Length);

                sendMsg[0] = (byte)MessageType.JSON;
                foreach (var item in this.OnLineList_list.SelectedItems)
                {
                    string client = item.ToString();

                    CurrentClientlist[client]?.Send(sendMsg);
                }
            }
            else
            {
                Addlog(1, "请选择你要发送的客户端！");
            }
        }
    }
}